package com.recursiveflow.openplatform.view 
{
    import com.gskinner.motion.GTween;
    import com.gu.tagbrowser.assets.StatusStrip;
    import com.gu.tagbrowser.assets.TagStrip;
    import com.guardian.apis.content.model.SearchQuery;
    import com.guardian.apis.content.model.Tag;

    import flash.display.Sprite;
    import flash.events.MouseEvent;
    import flash.filters.GlowFilter;
    import flash.geom.ColorTransform;
    import flash.text.TextFieldAutoSize;
    import flash.utils.Dictionary;

    /**
     * Status bar containing a strip of tags representing the search criteria in the order they have been applied.
     * 
     * Bar width is set dynamically based on a constructor parameter.
     * 
     * Tweens are used to slide new tags in from the LHS and then slide them back out again when they're done with.
     * 
     * Tags are coloured according to the section of the newspaper they correspond to.
     * 
     * Tags have their labels set dynamically and are then sized accordingly. 
     * 
     * Tags are related to their place in the search history via a pair of dictionaries.
     * 
     * @author Alastair Dant / Recursive Flow / 2009
     */
    public class StatusBar extends Sprite 
    {
        private static const OUTLINE : GlowFilter = new GlowFilter(0, 0.8, 3, 3, 3, 1, true);

        private var colourer : TagColourer;
        private var bar : StatusStrip;
        private var activeStripHolder : Sprite;
        private var defaultColour : ColorTransform;
        private var keywordStrip : TagStrip;
        private var stripQueryMap : Dictionary;
        private var queryStripMap : Dictionary;
        private var outgoingStripHolder : Sprite;

        public function StatusBar(w : Number, colourer : TagColourer)
        {
            this.colourer = colourer;
            this.defaultColour = new ColorTransform();
            this.defaultColour.color = 0x4f4f4f;
            
            this.stripQueryMap = new Dictionary();
            this.queryStripMap = new Dictionary();
            
            this.addChild(bar = new StatusStrip());
            this.addChild(outgoingStripHolder = new Sprite());
            this.addChild(activeStripHolder = new Sprite());
            
            this.bar.background.width = w;
        }

        public function setKeywords(query : SearchQuery) : void
        {
            keywordStrip = createStrip(getKeywordLegend(query.getKeywords()), defaultColour);
            
            keywordStrip.cap.visible = false;
            
            stripQueryMap[keywordStrip] = query;
            queryStripMap[query] = keywordStrip;
            
            addAtStart(keywordStrip);
        }

        public function add(query : SearchQuery, newTag : Tag) : void
        {
            var tagStrip : TagStrip = createStrip(newTag.getName(), colourer.getColorFor(newTag));
        	
            stripQueryMap[tagStrip] = query;
            queryStripMap[query] = tagStrip;
        	
            activateOthers();
            moveOthersBy(tagStrip.background.width + 5);
            addAtStart(tagStrip);
        	
            tagStrip.field.x += 5;
        }

        public function revertTo(query : SearchQuery) : void
        {
            var strip : TagStrip;
            var target : TagStrip = queryStripMap[query];
            var shrinkBy : Number = 0;
            var found : Boolean = false;	
            var index : int = activeStripHolder.numChildren;
            
            while (!found) 
            {
                strip = activeStripHolder.getChildAt(--index) as TagStrip;
	            
	            if (strip == target)
	            {
	            	found = true;
	            	
	                strip.buttonMode = false;
	        		
	                strip.removeEventListener(MouseEvent.ROLL_OVER, highlightStrip);            
	                strip.removeEventListener(MouseEvent.ROLL_OUT, dehighlightStrip);  
	                strip.removeEventListener(MouseEvent.CLICK, dispatchRevert);	            	
	            }
	            else
	            {
		            shrinkBy += strip.background.width + 5;
	            	remove(strip, shrinkBy);
	            }
            }         	
            
            do
            {
                strip = activeStripHolder.getChildAt(index) as TagStrip;
	        	moveBy(strip, shrinkBy);
            }         	
            while (--index >= 0);
        }

        private function getKeywordLegend(keywords : String) : String
        {
            return keywords.length == 0 ? "All items" : "Items containing \"" + keywords + "\"";
        }

        private function activateOthers() : void
        {
            var strip : TagStrip;
        	
            for (var i : int = 0;i < activeStripHolder.numChildren; i++) 
            {
                strip = activeStripHolder.getChildAt(i) as TagStrip;	
	            
                strip.buttonMode = true;
        		
                strip.addEventListener(MouseEvent.ROLL_OVER, highlightStrip);            
                strip.addEventListener(MouseEvent.ROLL_OUT, dehighlightStrip);  
                strip.addEventListener(MouseEvent.CLICK, dispatchRevert);  
            }         	
        }

        private function dispatchRevert(event : MouseEvent) : void
        {
            var q : SearchQuery = stripQueryMap[event.target];
            var e : SearchHistoryEvent = new SearchHistoryEvent(SearchHistoryEvent.REVERT, q);
            
            dispatchEvent(e);
        }
        
        private function moveBy(strip : TagStrip, shrinkBy : Number) : void
        {
        	new GTween(strip, 0.5, { x: strip.x - shrinkBy }); 
        }

        private function moveOthersBy(width : Number) : void
        {
            var strip : TagStrip, targetX : Number;
        	
            for (var i : int = 0;i < activeStripHolder.numChildren; i++) 
            {
                strip = activeStripHolder.getChildAt(i) as TagStrip;	
                targetX = strip.x + width;
                new GTween(strip, 0.5, { x: targetX });
            }         	
        }

        private function createStrip(title : String, colour : ColorTransform) : TagStrip
        {
            var ts : TagStrip = new TagStrip();
            
            ts.field.x = 20;
            ts.field.autoSize = TextFieldAutoSize.LEFT;
            ts.field.text = title;

            ts.background.transform.colorTransform = colour;
            ts.background.width = ts.field.width + 40;
            
            ts.cap.x = ts.background.width;
            ts.cap.fill.transform.colorTransform = colour;
            
            ts.mouseChildren = false;
            
            return ts;
        }

        private function highlightStrip(event : MouseEvent) : void
        {
            (event.target as TagStrip).filters = [OUTLINE];
        }

        private function dehighlightStrip(event : MouseEvent) : void
        {
            (event.target as TagStrip).filters = [];
        }

        private function addAtStart(strip : TagStrip) : void
        {
            activeStripHolder.addChild(strip);
            reveal(strip);
        }

        private function reveal(strip : TagStrip) : void
        {
            strip.x = -strip.width;
        	
            new GTween(strip, 0.5, { x : 0 }); 
        }

        private function remove(strip : TagStrip, shrinkBy : Number) : void
        {
            strip.removeEventListener(MouseEvent.ROLL_OVER, highlightStrip);            
            strip.removeEventListener(MouseEvent.ROLL_OUT, dehighlightStrip);  
            strip.removeEventListener(MouseEvent.CLICK, dispatchRevert);  
        	
            outgoingStripHolder.addChild(strip);
        	
        	new GTween(strip, 0.5, { x : strip.x - shrinkBy - strip.cap.width}); 
        }

        public function clear() : void
        {
            var strip : TagStrip;
        	
            while(activeStripHolder.numChildren > 0)
            {
                strip = activeStripHolder.getChildAt(0) as TagStrip;	
        		
                activeStripHolder.removeChild(strip);        		
            } 	 	
        	
            while(outgoingStripHolder.numChildren > 0)
            {
                strip = outgoingStripHolder.getChildAt(0) as TagStrip;	
        		
                outgoingStripHolder.removeChild(strip);        		
            } 	 	
        }
    }
}
